﻿using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Transactions;
using WCS.Infrastructure.Attr;
using WCS.Infrastructure.Dto.Request.Organization;
using WCS.Infrastructure.Dto.Request.Payment;
using WCS.Infrastructure.Dto.Response.Common;
using WCS.Infrastructure.EFCore;
using WCS.Infrastructure.IOC;
using WCS.Infrastructure.Tools;
using WCS.Repository.Interface;
using WCS.Service.Interface;

namespace WCS.Service.Instance
{
    [Inject]
    public class PaymentCodeService:BaseService, IPaymentCodeService
    {
        private readonly IUnitOfWork _unitOfWork;
        private readonly IConfiguration _configuration;
        private readonly ILogService _logService;
        private readonly IUserService _userService;
        private readonly PaymentCodeIOC _paymentCodeIOC;
        private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly IDividedService _dividedAgreementService;

        public PaymentCodeService(IConfiguration configuration, ILogService logService, IUnitOfWork unitOfWork, IUserService userService, 
            PaymentCodeIOC paymentCodeIOC ,IHttpContextAccessor httpContextAccessor, IDividedService dividedAgreementService)
        {
            _configuration = configuration;
            _logService = logService;
            _unitOfWork = unitOfWork;
            _userService = userService;
            _paymentCodeIOC = paymentCodeIOC;
            _httpContextAccessor = httpContextAccessor;
            _dividedAgreementService = dividedAgreementService;
        }

        /// <summary>
        /// 新增收款码
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<ApiResult> AddPaymentCodeAsync(PaymentCodeRequestDto dto)
        {
            try
            {
                using var scope = new TransactionScope(TransactionScopeOption.Required, TimeSpan.FromMinutes(2), TransactionScopeAsyncFlowOption.Enabled);

                if (string.IsNullOrEmpty(dto.MerchantId))
                {
                    var store = await _paymentCodeIOC._storeEFCore.QueryAll(d => d.Id == dto.StoreId).FirstOrDefaultAsync();
                    dto.MerchantId = store?.MerchantId;
                    var code = await _paymentCodeIOC._paymentCodeEFCore.QueryAll(d => d.StoreId == dto.StoreId && string.IsNullOrEmpty(d.ParentId)).FirstOrDefaultAsync();
                    dto.ParentId = code?.Id;
                }

                if (!string.IsNullOrEmpty(dto.DividedAgreementId))
                {
                    var dividedAgreement = await _paymentCodeIOC._dividedAgreementEFCore.QueryAll(d => d.Id == dto.DividedAgreementId).FirstOrDefaultAsync();

                    if (dividedAgreement == null || !DividedService.IsAgreementEffective(dividedAgreement, DateTime.Now))
                    {
                        return GetResult(message: "关联分账协议无效（已删除/未激活/未启用或不在有效期）");
                    }
                }
                PaymentCode paymentCode = new PaymentCode()
                {
                    Id = Config.GUID(),
                    StoreId = dto.StoreId,
                    Code = Config.GenerateCode(),
                    CodeName = dto.CodeName,
                    DividedAgreementId = dto.DividedAgreementId,
                    ParentId = dto.ParentId,
                    MerchantId = dto.MerchantId,
                    CodeUrl = "",
                    SettlementCycle = dto.SettlementCycle ?? 1,
                    CreationTime = DateTime.Now,
                    CreatorId = dto.CreatorId ?? _httpContextAccessor.HttpContext?.GetCurrentUserId(),
                    IsDeleted = false,
                    EnableStatus = 1,
                };

                await _paymentCodeIOC._paymentCodeEFCore.AddAsync(paymentCode);
                var paymentCodeResult = await _paymentCodeIOC._paymentCodeEFCore.SaveChangesAsync();

                if (paymentCodeResult == 0)
                {
                    return GetResult(message: "收款码生成失败，请稍后重试！");
                }

                scope.Complete();
                return GetResult(1, data: paymentCode.Id);

            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 编辑收款码
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<ApiResult> UpdatePaymentCodeAsync(PaymentCodeRequestDto dto)
        {
            try
            {
                using var scope = new TransactionScope(TransactionScopeOption.Required, TimeSpan.FromMinutes(2), TransactionScopeAsyncFlowOption.Enabled);

                var paymentCode = await _paymentCodeIOC._paymentCodeEFCore.QueryAll(d => d.Id == dto.Id).FirstOrDefaultAsync();
                if (paymentCode == null)
                {
                    return GetResult(message: "找不到此收款码，请稍后重试");
                }

                if (!string.IsNullOrEmpty(dto.DividedAgreementId))
                {
                    var dividedAgreement = await _paymentCodeIOC._dividedAgreementEFCore.QueryAll(d => d.Id == dto.DividedAgreementId).FirstOrDefaultAsync();

                    if (dividedAgreement == null || !DividedService.IsAgreementEffective(dividedAgreement, DateTime.Now))
                    {
                        return GetResult(message: "关联分账协议无效（已删除/未激活/未启用或不在有效期）");
                    }
                }

                paymentCode.CodeName = dto.CodeName;
                paymentCode.StoreId = dto.StoreId;
                paymentCode.DividedAgreementId = dto.DividedAgreementId;
                paymentCode.SettlementCycle = dto.SettlementCycle;
                paymentCode.LastModificationTime = DateTime.Now;
                paymentCode.LastModifierId = _httpContextAccessor.HttpContext?.GetCurrentUserId();
                //paymentCode.EnableStatus = (int)dto.EnableStatus;

                await _paymentCodeIOC._paymentCodeEFCore.UpdateAsync(paymentCode);
                var result = await _paymentCodeIOC._paymentCodeEFCore.SaveChangesAsync();

                if (result == 0)
                    return GetResult(message: "修改失败，请稍后重试！");

                scope.Complete();
                return GetResult(result);

            }
            catch (Exception)
            {

                throw;
            }

        }

        /// <summary>
        /// 获取单个收款码详情
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<ApiResult> GetPaymentCodeDetailAsync(PaymentCodeRequestDto dto)
        {
            var paymentCode = await _paymentCodeIOC._paymentCodeEFCore.QueryAll(d => (string.IsNullOrEmpty(dto.Id) || d.Id.Contains(dto.Id))
            && (string.IsNullOrEmpty(dto.Code) || d.Code.Contains(dto.Code))).Select(d => new PaymentCodeRequestDto
            {
                Id = d.Id,
                Code = d.Code,
                CodeName = d.CodeName,
                CodeUrl = d.CodeUrl,
                CreationTime = d.CreationTime,
                EnableStatus = d.EnableStatus,
                MerchantId = d.MerchantId,
                StoreId = d.StoreId,
                DividedAgreementId = d.DividedAgreementId,
                ParentId = d.ParentId,
                SettlementCycle = d.SettlementCycle,
            }).FirstOrDefaultAsync();

            if (paymentCode == null)
            {
                return GetResult(message: "找不到收款码详情");
            }

            var roleId = await _paymentCodeIOC._sysRoleEFCore.QueryAll(d => d.RoleType == 6).Select(d => d.Id).FirstOrDefaultAsync();
            paymentCode.StoreName = await _paymentCodeIOC._storeEFCore.QueryAll(d => d.Id == paymentCode.StoreId).Select(d => d.Name).FirstOrDefaultAsync();

            //查询收款码关联团队成员
            var userRole = await _paymentCodeIOC._sysUserRoleEFCore.QueryAll(d => d.MerchantId == paymentCode.MerchantId
            && d.StoreId == paymentCode.StoreId
            && d.CodeId == paymentCode.Id
            && d.RoleId == roleId).ToListAsync();

            userRole.ForEach(d =>
            {
                paymentCode.BindUserId.Add(d.Id);
                paymentCode.BindUserName.Add(d.Name);
            });

            return GetResult(1, data: paymentCode);
        }

        /// <summary>
        /// 获取收款码列表
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<ApiResult> GetPaymentCodeListAsync(PaymentCodeRequestDto dto)
        {
            var permission = await _userService.GetCurUserRolePermissionAsync();
            List<string> storeIds = new List<string>();
            List<string> codeIds = new List<string>();
            if (permission != null)
            {
                if (permission.RoleType == 4 || permission.RoleType == 5)//监事/店长
                {
                    storeIds = permission.StoreIds;
                    if (storeIds.Count() < 1)
                        return GetResult(1, "无关联数据");
                }
                else if (permission.RoleType == 6)//收银员
                {
                    codeIds = permission.CodeIds;
                    if (codeIds.Count() < 1)
                        return GetResult(1, "无关联数据");
                }

                if (storeIds.Count == 0 && !string.IsNullOrEmpty(dto.StoreId))
                    storeIds.Add(dto.StoreId);
            }

            var data = await _paymentCodeIOC._paymentCodeEFCore.QueryAll(out int total, dto.Page, dto.Limit,
                d => (string.IsNullOrEmpty(dto.Key) || d.Code.Contains(dto.Key))
                && (string.IsNullOrEmpty(dto.MerchantId) || d.MerchantId.Contains(dto.MerchantId))
                && (!storeIds.Any() || storeIds.Contains(d.StoreId))
                && (!codeIds.Any() || codeIds.Contains(d.Id))
                && (dto.QueryNoDividedAgreement == null || (dto.QueryNoDividedAgreement == true ? string.IsNullOrEmpty(d.DividedAgreementId) : !string.IsNullOrEmpty(d.DividedAgreementId))),
                d => d.CreationTime, false)
            .Select(d => new PaymentCodeRequestDto
            {
                Id = d.Id,
                StoreId = d.StoreId,
                MerchantId = d.MerchantId,
                Code = d.Code,
                CodeName = d.CodeName,
                ParentId = d.ParentId,
                CreationTime = d.CreationTime,
                EnableStatus = d.EnableStatus,
                DividedAgreementId = d.DividedAgreementId,
            }).ToListAsync();

            var roleId = await _paymentCodeIOC._sysRoleEFCore.QueryAll(d => d.RoleType == 6).Select(d => d.Id).FirstOrDefaultAsync();

            foreach (var paymentCode in data)
            {
                paymentCode.StoreName = await _paymentCodeIOC._storeEFCore.QueryAll(d => d.Id == paymentCode.StoreId).Select(d => d.Name).FirstOrDefaultAsync();

                //查询收款码关联团队成员
                var userRole = await _paymentCodeIOC._sysUserRoleEFCore.QueryAll(d => d.MerchantId == paymentCode.MerchantId
                && d.StoreId == paymentCode.StoreId
                && d.CodeId == paymentCode.Id
                && d.RoleId == roleId).ToListAsync();

                userRole.ForEach(d =>
                {
                    paymentCode.BindUserId.Add(d.Id);
                    paymentCode.BindUserName.Add(d.Name);
                });
            }

            return GetResult(1, data: new
            {
                data,
                total
            });
        }

        /// <summary>
        /// 在收款码详情里批量设置关联成员
        /// </summary>
        public async Task<ApiResult> SetPaymentCodeMembersAsync(BindMembersRequestDto dto)
        {
            try
            {
                if (string.IsNullOrEmpty(dto.CodeId))
                    return GetResult(message: "参数错误：收款码ID不能为空");

                var txOptions = new System.Transactions.TransactionOptions
                {
                    IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted, //防脏读
                    Timeout = TimeSpan.FromMinutes(2)
                };
                using var scope = new TransactionScope(TransactionScopeOption.Required, txOptions, TransactionScopeAsyncFlowOption.Enabled);

                var code = await _paymentCodeIOC._paymentCodeEFCore.QueryAll(d => d.Id == dto.CodeId).FirstOrDefaultAsync();
                if (code == null)
                    return GetResult(message: "找不到收款码，请稍后重试！");

                // Merchant 校验（若入参传了 MerchantId 则做一致性校验）
                if (!string.IsNullOrEmpty(dto.MerchantId) && !string.Equals(code.MerchantId, dto.MerchantId, StringComparison.OrdinalIgnoreCase))
                    return GetResult(message: "参数错误：商户不匹配");

                var targetIds = (dto.UserRoleIds ?? new List<string>()).Distinct().ToList();

                // 当前已绑定到该收款码的成员（注意查询条件包含 StoreId 与 CodeId）
                var currentIds = await _paymentCodeIOC._sysUserRoleEFCore.QueryAll(d =>
                        d.MerchantId == code.MerchantId && d.StoreId == code.StoreId && d.CodeId == code.Id)
                    .Select(d => d.Id)
                    .ToListAsync();

                var toUnbindIds = currentIds.Except(targetIds).ToList();
                var toBindIds = targetIds.Except(currentIds).ToList();

                int affected = 0;

                // 解绑：仅清理 CodeId，保留 StoreId（这样仍然在门店成员中）
                if (toUnbindIds.Count > 0)
                {
                    var unbindList = await _paymentCodeIOC._sysUserRoleEFCore.QueryAll(d =>
                            toUnbindIds.Contains(d.Id) && d.MerchantId == code.MerchantId && d.StoreId == code.StoreId && d.CodeId == code.Id)
                        .ToListAsync();

                    foreach (var ur in unbindList)
                    {
                        ur.CodeId = null;
                        ur.LastModificationTime = DateTime.Now;
                        ur.LastModifierId = _httpContextAccessor.HttpContext?.GetCurrentUserId();
                    }

                    if (unbindList.Count > 0)
                    {
                        await _paymentCodeIOC._sysUserRoleEFCore.UpdateRangeAsync(unbindList);
                        affected += await _paymentCodeIOC._sysUserRoleEFCore.SaveChangesAsync();
                    }
                }

                // 绑定：为目标收款码新增成员绑定记录（而不是改动原有记录），以支持“一个成员多个收款码”
                if (toBindIds.Count > 0)
                {
                    // 基准记录：用于取 UserId/RoleId/MerchantId/Name（不修改这些记录）
                    var baseList = await _paymentCodeIOC._sysUserRoleEFCore.QueryAll(d =>
                            toBindIds.Contains(d.Id) && d.MerchantId == code.MerchantId)
                        .ToListAsync();

                    if (baseList.Count > 0)
                    {
                        var baseUserIds = baseList.Select(x => x.UserId).Distinct().ToList();
                        var baseRoleIds = baseList.Select(x => x.RoleId).Distinct().ToList();

                        // 已存在于“当前收款码”的记录，做幂等判断（UserId+RoleId 维度）
                        var existAtThisCode = await _paymentCodeIOC._sysUserRoleEFCore.QueryAll(d =>
                                d.MerchantId == code.MerchantId
                                && d.StoreId == code.StoreId
                                && d.CodeId == code.Id
                                && baseUserIds.Contains(d.UserId)
                                && baseRoleIds.Contains(d.RoleId))
                            .Select(d => new { d.UserId, d.RoleId })
                            .ToListAsync();

                        var existKeys = new HashSet<string>(existAtThisCode.Select(e => $"{e.UserId}:{e.RoleId}"));

                        var newList = new List<SysUserRole>();
                        var creatorId = _httpContextAccessor.HttpContext?.GetCurrentUserId();

                        foreach (var br in baseList)
                        {
                            var key = $"{br.UserId}:{br.RoleId}";
                            if (existKeys.Contains(key))
                                continue; // 幂等：已有同人同角色绑定该码，跳过

                            newList.Add(new SysUserRole
                            {
                                Id = Config.GUID(),
                                UserId = br.UserId,
                                RoleId = br.RoleId,
                                MerchantId = code.MerchantId,
                                StoreId = code.StoreId, // 绑定到该码所在门店
                                CodeId = code.Id,       // 绑定该码
                                Name = br.Name,
                                CreationTime = DateTime.Now,
                                CreatorId = creatorId,
                                IsDeleted = false,
                                EnableStatus = 1,
                            });
                        }

                        if (newList.Count > 0)
                        {
                            await _paymentCodeIOC._sysUserRoleEFCore.AddRangeAsync(newList);
                            affected += await _paymentCodeIOC._sysUserRoleEFCore.SaveChangesAsync();
                        }
                    }
                }

                if (affected == 0)
                    return GetResult(message: "设置关联成员失败，请稍后重试！");

                scope.Complete();
                return GetResult(affected);
            }
            catch (Exception)
            {
                throw;
            }
        }
    }
}
